package com.atguigu.gmall.order.receiver;

import com.alibaba.fastjson.JSON;
import com.atguigu.gmall.enums.model.PaymentStatus;
import com.atguigu.gmall.enums.model.ProcessStatus;
import com.atguigu.gmall.order.model.OrderInfo;
import com.atguigu.gmall.order.service.OrderInfoService;
import com.atguigu.gmall.rabbit.config.MqConst;
import com.rabbitmq.client.Channel;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.Stack;
import java.util.concurrent.TimeUnit;


/**
 * @author: atguigu
 * @create: 2023-08-12 11:35
 */
@Slf4j
@Component
public class OrderReceiver {


    @Autowired
    private OrderInfoService orderInfoService;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 监听延迟关闭订单消息
     *
     * @param orderId 订单ID
     * @param message
     * @param channel
     */
    @SneakyThrows
    @RabbitListener(queues = MqConst.QUEUE_ORDER_CANCEL)
    public void processCancelOrder(Long orderId, Message message, Channel channel) {
        if (orderId != null) {
            log.info("[订单服务]监听到订单关闭消息：{}", orderId);
            //1.调用业务层完成订单状态验证以及关闭
            orderInfoService.execExpireOrder(orderId);
            //2.手动应答消息
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        }
    }


    /**
     * 监听支付成功消息，完成订单状态修改
     *
     * @param orderId 订单ID
     * @param message
     * @param channel
     */
    @SneakyThrows
    @RabbitListener(bindings = @QueueBinding(
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_PAYMENT_PAY, durable = "true"),
            value = @Queue(value = MqConst.QUEUE_PAYMENT_PAY, durable = "true"),
            key = MqConst.ROUTING_PAYMENT_PAY
    ))
    public void processPaySucess(Long orderId, Message message, Channel channel) {
        if (orderId != null) {
            log.info("[订单服务]监听到支付成功消息，订单ID：{}", orderId);
            //1.业务处理
            String key = "mq:" + orderId + ":md";
            Boolean flag = redisTemplate.opsForValue().setIfAbsent(key, orderId, 10, TimeUnit.MINUTES);
            if (!flag) {
                channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
                return;
            }
            //1.1 调用业务层完成订单状态修改
            orderInfoService.updateOrderStatus(orderId, ProcessStatus.PAID);
            //1.2 发送MQ消息通知库存系统进行【拆单】锁定商品库存 -- 分析得知库存系统不允许同一订单多次进行商品锁定，做好幂等性处理
            orderInfoService.sendLockStockMsg(orderId);
            //2.手动应答消息
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        }
    }


    /**
     * 监听库存系统反馈锁定库存结果
     * 根据锁定库存结果更新订单状态
     *
     * @param stockLockStr
     * @param message
     * @param channel
     */
    @SneakyThrows
    @RabbitListener(bindings = @QueueBinding(
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_WARE_ORDER, durable = "true"),
            value = @Queue(value = MqConst.QUEUE_WARE_ORDER, durable = "true"),
            key = MqConst.ROUTING_WARE_ORDER
    ))
    public void processStockLockResult(String stockLockStr, Message message, Channel channel) {
        if (StringUtils.isNotBlank(stockLockStr)) {
            log.info("[订单服务]监听库存锁定结果：{}", stockLockStr);

            //根据库存提交扣减结果修改订单状态
            Map map = JSON.parseObject(stockLockStr, Map.class);
            String orderId = (String) map.get("orderId");
            String status = (String) map.get("status");
            if ("DEDUCTED".equals(status)) {
                orderInfoService.updateOrderStatus(Long.valueOf(orderId), ProcessStatus.WAITING_DELEVER);
            }
            if("OUT_OF_STOCK".equals(status)){
                orderInfoService.updateOrderStatus(Long.valueOf(orderId), ProcessStatus.STOCK_EXCEPTION);
            }
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        }
    }
}
